package cn.lingyangwl.agile.infra.weixin.cp.controller;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import cn.lingyangwl.agile.dynamic.config.core.ConfigFactory;
import cn.lingyangwl.agile.infra.weixin.cp.model.WxCpContext;
import cn.lingyangwl.agile.infra.weixin.cp.model.rqrs.MpCpOpenHandleMessageReq;
import cn.lingyangwl.agile.infra.weixin.cp.process.WxCpProcess;
import cn.lingyangwl.agile.infra.weixin.mp.model.rqrs.MpOpenHandleMessageReq;
import cn.lingyangwl.agile.model.enums.ConfigDefineEnum;
import cn.lingyangwl.agile.model.module.config.ConfigInfo;
import cn.lingyangwl.agile.tenant.core.utils.TenantUtils;
import com.alibaba.fastjson2.JSON;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.cp.api.WxCpService;
import me.chanjar.weixin.cp.bean.message.WxCpXmlMessage;
import me.chanjar.weixin.cp.bean.message.WxCpXmlOutMessage;
import me.chanjar.weixin.cp.message.WxCpMessageRouter;
import me.chanjar.weixin.cp.util.crypto.WxCpCryptUtil;
import org.springframework.context.annotation.Lazy;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.Objects;

/**
 * @author shenguangyang
 */
@Slf4j
@Api(tags = "对企业微信开放的接口")
@RestController
@RequestMapping
public class WxCpOpenController {
    @Resource
    @Lazy
    private WxCpProcess wxCpProcess;
    @Resource
    private ConfigFactory configFactory;

    /**
     * 接收企业微信的校验签名
     * <a href="https://developer.work.weixin.qq.com/document/path/90930>地址</a>
     * 配置接口后点击提交, 微信验证地址是否合法会向配置的地址发送一个get请求
     * @param tenantId 租户id
     */
    @GetMapping(value = "/open/wxCp/{tenantId}")
    public String checkSignature(@RequestParam("msg_signature") String signature,
                              @RequestParam("timestamp") String timestamp,
                              @RequestParam("nonce") String nonce,
                              @PathVariable("tenantId") String tenantId,
                              @RequestParam("echostr") String echoStr) {
        return TenantUtils.execute(tenantId, () -> {
            ConfigInfo configInfo = configFactory.getConfig(ConfigDefineEnum.WX_CP);
            if (Objects.isNull(configInfo)) {
                log.warn("尚未配置或者使能企业微信参数");
                return "fail";
            }
            // 校验签名
            WxCpService service = wxCpProcess.getContext().getService();
            if (service.checkSignature(signature, timestamp, nonce, echoStr)){
                // 校验成功返回echoStr的解密内容
                return new WxCpCryptUtil(service.getWxCpConfigStorage()).decrypt(echoStr);
            }
            // 校验失败
            return "fail";
        });
    }


    /**
     * 接收微信公众号的消息推送
     *
     * <a href="https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Receiving_standard_messages.html">文档</a>
     */
    @PostMapping(value = "/open/wxCp/{tenantId}",  produces = "application/xml; charset=UTF-8")
    public String handleMessage(@PathVariable("tenantId") String tenantId,
                                @RequestBody String content,
                                MpCpOpenHandleMessageReq req) {

        return TenantUtils.execute(tenantId, () -> {
            log.info("[handleMessage][tenantId({}) 推送消息，参数({}) 内容({})]", tenantId, req, content);
            try {
                ConfigInfo config = configFactory.getConfig(ConfigDefineEnum.WX_CP);
                if (Objects.isNull(config)) {
                    log.warn("尚未配置或者使能企业微信参数");
                    return "fail";
                }

                return handleMessage0(content, req);
            } catch (Exception e) {
                log.error("error: {}", e.getMessage());
            }
            return "fail";
        });
    }

    private String handleMessage0(String content, MpCpOpenHandleMessageReq req) {
        WxCpContext context = wxCpProcess.getContext();
        // 校验请求签名
        WxCpService cpService = context.getService();
        Assert.isTrue(cpService.checkSignature(req.getSignature(), req.getTimestamp(), req.getNonce(), content),
                "非法请求");

        // 第一步，解析消息
        WxCpXmlMessage inMessage = null;
        if (StrUtil.isBlank(req.getEncrypt_type())) { // 明文模式
            inMessage = WxCpXmlMessage.fromXml(content, context.getParam().getAgentId());
        } else if (Objects.equals(req.getEncrypt_type(), MpOpenHandleMessageReq.ENCRYPT_TYPE_AES)) { // AES 加密模式
            inMessage = WxCpXmlMessage.fromEncryptedXml(content, cpService.getWxCpConfigStorage(),
                    req.getTimestamp(), req.getNonce(), req.getMsg_signature());
        }
        if (Objects.isNull(inMessage)) {
            log.error("消息解析失败，原因：消息为空");
            return "fail";
        }
        log.info("消息解密后内容为: {}", JSON.toJSONString(inMessage));

        // 第二步，处理消息
        WxCpMessageRouter router = context.getRouter();
        WxCpXmlOutMessage outMessage = router.route(inMessage);
        if (outMessage == null) {
            log.error("outMessage is null");
            return "fail";
        }

        // 第三步，返回消息
        if (Objects.equals(req.getEncrypt_type(), MpOpenHandleMessageReq.ENCRYPT_TYPE_AES)) { // AES 加密模式
            return outMessage.toEncryptedXml(cpService.getWxCpConfigStorage());
        } else {
            log.warn("未处理的加密类型消息, encrypt_type: {}", req.getEncrypt_type());
        }
        return "fail";
    }
}
